home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / seyon / SeScan.c < prev    next >
C/C++ Source or Header  |  1995-05-03  |  8KB  |  285 lines

  1. /*---------------------------------------------------------------------------+
  2. | Free form input scanner
  3. +---------------------------------------------------------------------------*/
  4. #include <stdio.h>
  5. #include <assert.h>
  6. #include <stdlib.h>
  7. #include <ctype.h>
  8. #include <string.h>
  9. #include "SeParse.h"
  10. #include "y.tab.h"
  11.  
  12. /*---------------------------------------------------------------------------+
  13. | parse buffer - stores the string to be parsed (logical line)
  14. +---------------------------------------------------------------------------*/
  15. static unsigned parseBufLen;
  16. static unsigned parseBufNextCh;
  17. static char*     parseBuf;
  18.  
  19. void scSetInputBuffer(char *line) 
  20. {
  21.   assert(line != 0);
  22.   parseBufNextCh     = 0;
  23.   parseBufLen          = strlen(line);
  24.   parseBuf        = line;
  25. }
  26.  
  27. int scGetChar() {
  28.   if (parseBufNextCh < parseBufLen) {
  29. #ifdef TEST
  30.     printf("Reading char %c\n", parseBuf[parseBufNextCh]);
  31. #endif
  32.     return parseBuf[parseBufNextCh++];
  33.   }
  34.   else
  35.     return EOF;
  36. }
  37.  
  38. void scUngetChar(int c) {
  39.   if (parseBufNextCh > 0)
  40.     parseBuf[--parseBufNextCh] = c;
  41. }
  42.  
  43. int scLook() {
  44.   if (parseBuf != 0)
  45.     return parseBuf[parseBufNextCh];
  46.   else
  47.     return EOF;
  48. }
  49.  
  50. /*---------------------------------------------------------------------------+
  51. | strBuf - stores word to be returned
  52. +---------------------------------------------------------------------------*/
  53. #define GROW_SIZE 100
  54. static char *strBuf = 0;
  55. static unsigned strBufSize = 0;
  56. static unsigned strBufNextCh = 0;
  57.  
  58. static void _growBuf(unsigned size) {
  59.   if (strBuf == 0)
  60.     strBuf = (char *)malloc(strBufSize = size + GROW_SIZE);
  61.   else if (strBufSize < (strBufNextCh + size + 1)) {
  62.     strBufSize += (size + 1) + GROW_SIZE;
  63.     strBuf = (char *)realloc(strBuf, strBufSize);
  64.   }
  65. }
  66.  
  67. static void _startWord() {
  68.   strBufNextCh = 0;
  69. }
  70.  
  71. static void _addCh(int ch) {
  72.   _growBuf(1);
  73.   strBuf[strBufNextCh++] = ch;
  74. }
  75.  
  76. static char* _getWd() {
  77.   if (strBuf != 0) strBuf[strBufNextCh] = 0;
  78.   strBufNextCh = 0;
  79.   return strBuf;
  80. }
  81.  
  82. /*---------------------------------------------------------------------------+
  83. | scanner state
  84. +---------------------------------------------------------------------------*/
  85. enum SC_STATE {
  86.   SC_IN_WORD,
  87.   SC_IN_STR,
  88.   SC_OUTSIDE,
  89. };
  90.  
  91. static ScanState = SC_OUTSIDE;
  92. static ScanDelim = 0;    /* Current string delimiter */
  93.  
  94. void NEW_STATE(int st) {
  95.  
  96. #ifdef TEST
  97.   static char* state_names[] = { "InWord", "InStr", "Out", "NONE" };
  98.   printf("**Entering state %s\n", state_names[st]);
  99. #endif
  100.  
  101.   ScanState = st;
  102. }
  103.  
  104. #define C_ESC BACK_CHAR
  105. #define C_SPACE ' '
  106. #define C_SEP ';'
  107. #define C_STR '"'
  108.  
  109. int cType(int c) {
  110.   if (isspace(c)) return C_SPACE;
  111.   switch (c) {
  112.   case CTRL_CHAR: case BACK_CHAR: return C_ESC;
  113.   case ';' : case ',' : case '(' : case ')' : return C_SEP;
  114.   case '"' : case '\'' : return C_STR;
  115.   default : return c;
  116.   }
  117. }
  118.  
  119. int doEsc(int c);
  120.  
  121. /*---------------------------------------------------------------------------+
  122. | scNextWord breaks lines into sequences of words
  123. |
  124. | Args: recognize_seps - 1 == recognize and return "();,"
  125. |             0 == ignore those and put them into words
  126. |    wd - pointer to last recognized word, = 0 if at end of line
  127. |
  128. | Returns: input token type (usually a representative char)
  129. +---------------------------------------------------------------------------*/
  130. int scNextWord(int recognize_seps, char **wd)
  131. {
  132.   int c;
  133.  
  134.   while ((c = scGetChar()) != EOF) {
  135.     switch (ScanState) {
  136.     case SC_OUTSIDE:
  137.       switch (cType(c)) {
  138.       case C_ESC: NEW_STATE(SC_IN_WORD); _startWord(); _addCh(doEsc(c)); break;
  139.       case C_SPACE:                             break;
  140.       case C_SEP: if (recognize_seps) return c; 
  141.           else {
  142.             NEW_STATE(SC_IN_WORD); _startWord(); _addCh(c);
  143.           }                            break;
  144.       case C_STR: NEW_STATE(SC_IN_STR);  _startWord(); ScanDelim = c;     break;
  145.       default:    NEW_STATE(SC_IN_WORD); _startWord(); _addCh(c);    break;
  146.       }
  147.       break;
  148.  
  149.     case SC_IN_STR:
  150.       switch (cType(c)) {
  151.       case C_STR: 
  152.     if (ScanDelim == c) { NEW_STATE(SC_OUTSIDE); *wd = _getWd(); 
  153.                   return WORD;
  154.                 }
  155.     else  _addCh(c);                        break;
  156.       case C_ESC: _addCh(doEsc(c));                     break;
  157.       default:      _addCh(c);                         break;
  158.       }
  159.       break;
  160.  
  161.     case SC_IN_WORD:
  162.       switch (cType(c)) {
  163.       case C_ESC: _addCh(doEsc(c));                     break;
  164.       case C_STR: NEW_STATE(SC_IN_STR); ScanDelim = c;             break;
  165.       case C_SEP: 
  166.     if (recognize_seps) {
  167.       ScanState = SC_OUTSIDE; *wd = _getWd(); scUngetChar(c); 
  168.       return WORD;
  169.     }
  170.     else      _addCh(c);                        break;
  171.       case C_SPACE: NEW_STATE(SC_OUTSIDE); *wd = _getWd(); return WORD;break;
  172.       default: _addCh(c);                        break;
  173.       }
  174.       break;
  175.  
  176.     default: perror("Unknown state"); abort();
  177.       break;
  178.     }
  179.   }
  180.  
  181.   switch(ScanState) {
  182.   case SC_IN_WORD: *wd = _getWd(); NEW_STATE(SC_OUTSIDE); return WORD; 
  183.   case SC_IN_STR:  *wd = _getWd(); NEW_STATE(SC_OUTSIDE); return WORD; 
  184.   case SC_OUTSIDE: return 0;
  185.   default:  perror("Unknown state"); abort();
  186.   }
  187. }
  188.  
  189. /*---------------------------------------------------------------------------+
  190. | getOct - read an octal number with up to 3 digits
  191. +---------------------------------------------------------------------------*/
  192. int getOct()
  193. {
  194.   char intstr[4]; int next = 0;
  195.   int ch;
  196.  
  197.   while ((ch = scGetChar()) != EOF && next <= 3) 
  198.     if (isdigit(ch))
  199.       intstr[next++] = ch;
  200.     else if (ch != EOF) { 
  201.       scUngetChar(ch); 
  202.       break;
  203.     }
  204.   
  205.   intstr[next]=0;
  206.   return strtol(intstr, NULL,  8);
  207. }
  208.     
  209. /*---------------------------------------------------------------------------+
  210. | Mapping table for the \[a-z] sequences: we let the C compiler initialize
  211. | them for us... Of course we can change the value of a particular char if
  212. | we feel like it.
  213. +---------------------------------------------------------------------------*/
  214. static char special[26] = 
  215. { '\a', '\b', 'c', 'd', 'e', '\f', 'g', 'h', 'i', 'j', 'k', 'l', 
  216.   'm', '\n', 'o', 'p', 'q', '\r', 's', '\t', 'u', '\v', 'w', 'x',
  217.   'y', 'z'
  218. };
  219.  
  220. /*---------------------------------------------------------------------------+
  221. | doEsc - process esc (\) and control (^) sequences
  222. +---------------------------------------------------------------------------*/
  223. int doEsc(int escChar) {
  224.  
  225.   int     c = scGetChar();
  226.  
  227.   switch (escChar) {
  228.   case BACK_CHAR:
  229.          if (c == EOF) return escChar;
  230.     else if (isdigit(c)) { scUngetChar(c); return getOct(); }
  231.     else if (islower(c)) return special[c - 'a'];
  232.     else return c;
  233.     break;
  234.  
  235.   case CTRL_CHAR: 
  236.     if        (islower(c)) return c - 'a' + 1;
  237.     else if (isupper(c)) return c - 'A' + 1;
  238.     else   { scUngetChar(c);  return escChar;  }
  239.     break;
  240.  
  241.   default:
  242.     perror("Unknown escape sequence"); abort();
  243.   }
  244. }
  245.  
  246. /*---------------------------------------------------------------------------+
  247. | yylex - interface with yacc parser generator
  248. +---------------------------------------------------------------------------*/
  249. int yylex() 
  250. {
  251.   int state = scNextWord(1, &yylval.sval);
  252.   return state;
  253. }
  254.  
  255. /*---------------------------------------------------------------------------+
  256. | GetWord - return successive words in input line, 0 when finished
  257. +---------------------------------------------------------------------------*/
  258. char*
  259. GetNextWord() 
  260. {
  261.   char *word;
  262.  
  263.   if (scNextWord(0, &word) == 0) return "";
  264.   return word;
  265. }
  266.  
  267. char*
  268. GetFirstWord(line) 
  269.      char *line;
  270. {
  271.   scSetInputBuffer(line);
  272.   return GetNextWord();
  273. }
  274.  
  275. #ifdef TEST
  276. main()
  277. {
  278.   scSetInputBuf("Just to see if we'\\'re \\n\\033 able to distinguish' words and strings
  279. \"Also 'quotes' inside strings\" and 'strs \"inside quotes\"'
  280. Not to forget ^S and ^q control ^ chars");
  281.  
  282.   while (lGetWord() != 0);
  283. }
  284. #endif
  285.